﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExcelLibrary;
using ExcelLibrary.SpreadSheet;
using ExcelLibrary.CompoundDocumentFormat;
using ExcelLibrary.BinaryFileFormat;
using ExcelLibrary.BinaryDrawingFormat;
using CSharpCity.Tools.RandomNumberGenerators;

namespace SimulacionAgrofoods
{
    public class Simulador
    {
        List<Lote> lotes;
        List<Frio> frios;
        List<Lote> lotesn;
        List<Frio> friosn;
        Dictionary<int, int> demandas;
        Lote lote1;
        Frio frio1;
        Lote lote;
        Frio frio;
        Frio friointerno = new Frio(1600, 75, "Interno");
        Frio friointerno1 = new Frio(1600, 75, "Interno");
        int fecha;
        int demanda;
        int _costos_totales = 0;
        Workbook workbook = new Workbook();
        Worksheet worksheet2;
        Worksheet worksheet3;
        string _path;

        public void Inicializar(int desviacion)
        {
            //Crear listas
            lotes = new List<Lote>();
            frios = new List<Frio>();
            lotesn = new List<Lote>();
            friosn = new List<Frio>();
            demandas = new Dictionary<int, int>();
            friointerno = new Frio(1600, 75, "Interno");
            friointerno1 = new Frio(1600, 75, "Interno");
            //Crear nueva sheet
            worksheet3 = new Worksheet("Desviacion");


            //Agregamos el frio interno
            frios.Add(friointerno);
            friosn.Add(friointerno1);
            // open xls file
            Workbook book = Workbook.Load(_path);
            Worksheet sheet = book.Worksheets[0];

            // Inicializar Lotes 
            for (int rowIndex = sheet.Cells.FirstRowIndex+1;
                   rowIndex <= sheet.Cells.LastRowIndex; rowIndex++)
            {
                Row row = sheet.Cells.GetRow(rowIndex);

                int fecha = Int32.Parse(row.GetCell(0).Value.ToString());
                int cantidad = Int32.Parse(row.GetCell(1).Value.ToString());
                //
                worksheet3.Cells[rowIndex, 0] = new Cell(cantidad);
                //
                cantidad = (int)Normal_Random(cantidad, (double)desviacion/(double)100);
                //
                worksheet3.Cells[rowIndex, 1] = new Cell(cantidad);
                //
                int duracion = Int32.Parse(row.GetCell(2).Value.ToString());
                duracion = (int)(Normal_Random(duracion, (double)desviacion/(double)100) * 0.7);

                lote = new Lote(fecha, cantidad, duracion);
                lote1 = new Lote(fecha, cantidad, duracion);
                lotes.Add(lote);
                lotesn.Add(lote1);
            }

            Worksheet sheet2 = book.Worksheets[1];
            
            // Inicializar Frios
            for (int rowIndex = sheet2.Cells.FirstRowIndex+1;
                   rowIndex <= sheet2.Cells.LastRowIndex; rowIndex++)
            {
                Row row = sheet2.Cells.GetRow(rowIndex);

                int tipo = Int32.Parse(row.GetCell(0).Value.ToString());

                if (tipo == 0) 
                {
                    int costo_variable = Int32.Parse(row.GetCell(1).Value.ToString());
                    int numeral = Int32.Parse(row.GetCell(2).Value.ToString());
                    int capacidad_maxima = Int32.Parse(row.GetCell(3).Value.ToString());
                    int zona = Int32.Parse(row.GetCell(4).Value.ToString());
                    int capacidad_camara = Int32.Parse(row.GetCell(5).Value.ToString());
                    string nombre = row.GetCell(6).Value.ToString();

                    frio = new Frio(costo_variable, numeral, capacidad_maxima, zona, capacidad_camara, nombre);
                    frio1 = new Frio(costo_variable, numeral, capacidad_maxima, zona, capacidad_camara, nombre);
                }

                else
                {
                    int costo_fijo = Int32.Parse(row.GetCell(1).Value.ToString());
                    int capacidad_maxima = Int32.Parse(row.GetCell(3).Value.ToString());
                    int zona = Int32.Parse(row.GetCell(4).Value.ToString());
                    int capacidad_camara = Int32.Parse(row.GetCell(5).Value.ToString());
                    string nombre = row.GetCell(6).Value.ToString();

                    frio = new Frio(costo_fijo, capacidad_maxima, zona, capacidad_camara, nombre);
                    frio1 = new Frio(costo_fijo, capacidad_maxima, zona, capacidad_camara, nombre);
                }

                frios.Add(frio);
                friosn.Add(frio1);
            }

            Worksheet sheet3 = book.Worksheets[2];

            // Inicializar Demandas
            for (int rowIndex = sheet3.Cells.FirstRowIndex+1;
                   rowIndex <= sheet3.Cells.LastRowIndex; rowIndex++)
            {
                Row row = sheet3.Cells.GetRow(rowIndex);

                fecha = Int32.Parse(row.GetCell(0).Value.ToString());
                demanda = Int32.Parse(row.GetCell(1).Value.ToString());
                demanda = (int)Normal_Random(demanda, (double)desviacion / (double)100);

                demandas.Add(fecha, demanda);
            }
            
        }

        public void simular(int simulaciones, int desviacion) {

            Simulacion Sim_H_A = new Simulacion();
            Simulacion Sim_H_N = new Simulacion();
            worksheet2 = new Worksheet("Simulaciones");
            for (int i = 0; i < simulaciones; i++) {
                this.Inicializar(desviacion);

                Sim_H_A.reset(lotes, frios, demandas);
                Sim_H_N.reset(lotesn, friosn, demandas);

                int costos_a = Sim_H_A.Simular(false, 180);
                int costos_n = Sim_H_N.Simular(true, 180);

                Exportar_Simulaciones(i, costos_a, costos_n);
            }

           
        }

        public void Exportar(string path) 
        {
            //create new xls file

            string file = path + "\\Resumen Frios.xls";

            Worksheet worksheet = new Worksheet("Totales");
            worksheet.Cells[0, 0] = new Cell("Nombre Frío");
            worksheet.Cells[0, 1] = new Cell("Bins Enviados");
            worksheet.Cells[0, 2] = new Cell("Costo Envíos");
            worksheet.Cells[0, 3] = new Cell("Costo Frío");

            for (int i = 0; i < frios.Count; i++)
            {
                worksheet.Cells[i+1, 0] = new Cell(friosn[i].Nombre);
                worksheet.Cells[i+1, 1] = new Cell(friosn[i].Bins_Totales);
                worksheet.Cells[i+1, 2] = new Cell(friosn[i].Costos_Envios);
                worksheet.Cells[i+1, 3] = new Cell(friosn[i].get_Costos());
            }
            worksheet.Cells[frios.Count+1, 3] = new Cell(_costos_totales);
            
            //Fix error
            for (int i = 0; i < 100; i++)
            {
                worksheet.Cells[i, 5] = new Cell(" ");
            }
            //
            workbook.Worksheets.Add(worksheet);
            workbook.Worksheets.Add(worksheet2);
            workbook.Worksheets.Add(worksheet3);
            workbook.Save(file);

        }

        public void Exportar_Detalle(int dia, int demanda, int vencidos, int llegada, int a_frios) 
        {
                worksheet2.Cells[dia, 0] = new Cell(dia);
                worksheet2.Cells[dia, 1] = new Cell(demanda);
                worksheet2.Cells[dia, 2] = new Cell(vencidos);
                worksheet2.Cells[dia, 3] = new Cell(llegada); 
                worksheet2.Cells[dia, 4] = new Cell(a_frios);
        }

        public void Exportar_Simulaciones(int numero, int costos_a, int costos_n )
        {
            worksheet2.Cells[numero, 0] = new Cell(numero);
            worksheet2.Cells[numero, 1] = new Cell(costos_a);
            worksheet2.Cells[numero, 2] = new Cell(costos_n);
        }

        public string Path { get { return _path; } set { _path = value; } }

        public double Normal_Random(double mean, double stdDev)
        {
            List<double> valores = new List<double>();
            for (int i = 0; i < 100; i++) 
            {
                double valor = 0;
                Random rand = new Random();
                double min = 0;
                double max = 0;

                if (i < 1) 
                {
                    min = (1 - (3 * stdDev)) * mean;
                    max = (1 - (2 * stdDev)) * mean;
                }
                else if (i < 2) 
                {
                    min = (1 + (2 * stdDev)) * mean;
                    max = (1 + (3 * stdDev)) * mean;
                }
                else if (i < 16) 
                {
                    min = (1 - (2 * stdDev)) * mean;
                    max = (1 - (1 * stdDev)) * mean;
                }
                else if (i < 30) 
                {
                    min = (1 + (1 * stdDev)) * mean;
                    max = (1 + (2 * stdDev)) * mean;
                }
                else if (i < 65) 
                {
                    min = (1 - (1 * stdDev)) * mean;
                    max = mean;
                }
                else if (i < 100) 
                {
                    min = mean;
                    max = (1 + (1 * stdDev)) * mean;
                }

                valor = rand.NextDouble() * (max - min) + min;
                valores.Add(valor);
            }
            Random r = new Random();
            
            return valores[r.Next(valores.Count)];
        }
    }
}
